#include "Renderer/font.h"
#include <unordered_map>
#include <string>
#include "Core/utils.h"
#include <locale>
#include <codecvt>
#include "Renderer/texture.h"

namespace CC
{
    // Unicode
    static std::unordered_map<std::string, FT_ULong> CharacterForms;
    static std::unordered_map<std::string, Character> Characters50px;
    static std::unordered_map<std::string, Character> Characters100px;

    static std::unordered_map<wchar_t, Character> WCharactersDefault;

    signed long GetCharacterIndex(std::string c)
    {
        std::unordered_map<std::string, FT_ULong>::iterator it = CharacterForms.find(c);
        if (it != CharacterForms.end())
        {
            return it->second;
        }
        return -1;
    }

    void ParseUnicode(std::string file)//utf8 no bom
    {
        std::vector<std::string> data;
        FileLog::ReadFile(file, data);

        int startIndex = 0x4E00;
        // start 4e00 [0123456789ABCDEF]
        int size = data.size();
        for (int i = 0; i < size; i++)
        {
            int strSize = data[i].size();
            CC_CORE_INFO("--------ParseUnicode strSize %d--\n", strSize);

            for (int j = 0; j < strSize; j += 3)
            {
                std::string name = data[i].substr(j, 3);
                // std::string nameUtf8;//3char
                // FileLog::Unicode2Utf8(name, nameUtf8);

                CharacterForms[name] = startIndex;
                startIndex++;

                // CC_CORE_INFO("--------ParseUnicode strSize(%d) %s:%x--\n", j, name.c_str(), CharacterForms[name]);

            }
        }
        CC_CORE_INFO("--------ParseUnicode %d--\n", size);
    }

    Character &LoadCharacter(const Font &font, std::string name, unsigned int fontSize)
    {
        FT_Set_Pixel_Sizes(font.face, 0, fontSize);
        std::string one = name;
        signed long char_code;

        int len = name.size();
        if (len == 3)
        {
            char_code = GetCharacterIndex(one);
        }
        else if (len == 2)
        {
            char_code = GetCharacterIndex(one);
        }
        else if (len == 1)
        {
            char_code = one[0];
        }
        else
        {
            CC_ASSERT(false, "ASSERT: LoadCharacter len (%d) error.\n", len);
        }

        // CC_CORE_INFO("LoadCharacter %d: %s, %ld\n", 0, one.c_str(), char_code);

        if (FT_Load_Char(font.face, char_code, FT_LOAD_RENDER))
            std::cout << "ERROR::FREETYTPE: Failed to load Glyph:" << one.c_str() << std::endl;

        Texture2D *texture = Texture2D::Create(font);
        Character character = {
            texture,
            glm::ivec2(font.face->glyph->bitmap.width, font.face->glyph->bitmap.rows),
            glm::ivec2(font.face->glyph->bitmap_left, font.face->glyph->bitmap_top),
            (GLuint)font.face->glyph->advance.x,
            fontSize};

        if (fontSize > FONTCACHEVALUE)
        {
            Characters100px[one] = character;
            return Characters100px[one];
        }
        else
        {
            Characters50px[one] = character;
            return Characters50px[one];
        }
    }

    Character &GetCharacter(std::string name, unsigned int fontSize)
    {
        if (fontSize > FONTCACHEVALUE)
        {
            return Characters100px[name];
        }
        return Characters50px[name];
    }

    Character *LoadCharacterW(const Font &font, wchar_t &char_code, unsigned int fontSize)
    {

        Character* character = GetCharacterW(char_code, fontSize);

        if (character && character->texture2D)
        {
            // auto load charater
            return character;
        }

        FT_Set_Pixel_Sizes(font.face, 0, fontSize);

        if (FT_Load_Char(font.face, static_cast<FT_ULong>(char_code), FT_LOAD_RENDER))
            std::cout << "ERROR::FREETYTPE: Failed to load Glyph:" << static_cast<FT_ULong>(char_code) << std::endl;

        Texture2D *texture = Texture2D::Create(font);
        Character character_new = {
            texture,
            glm::ivec2(font.face->glyph->bitmap.width, font.face->glyph->bitmap.rows),
            glm::ivec2(font.face->glyph->bitmap_left, font.face->glyph->bitmap_top),
            (GLuint)font.face->glyph->advance.x,
            fontSize };

        WCharactersDefault[char_code] = character_new;
        return &WCharactersDefault[char_code];
    }

    Character *GetCharacterW(wchar_t& char_code, unsigned int fontSize)
    {
        std::unordered_map<wchar_t, Character>::iterator it = WCharactersDefault.find(char_code);
        if (it == WCharactersDefault.end()) {
            return nullptr;
        }
        return &it->second;
        //return WCharactersDefault[char_code];
    }

   
}